﻿#ifndef __AVOID_CONTROL_SCROLL_HEAD_FILE_INCLUDED__
#define __AVOID_CONTROL_SCROLL_HEAD_FILE_INCLUDED__
#include "control.h"
#include "ctlButton.h"
#include "interface/ISmoothTransform.h"
#include <atomic>

namespace swui
{
#pragma warning(push)
#pragma warning(disable:4250)
	class ctlScroll : virtual public ctlRoot, 
		public ISmoothTransform
	{
	public:
		static const ctlControlType uniqueType = ctlControlType::ctlScroll;
	public:
		virtual ~ctlScroll() { destroy(); }
		bool create(ctlRoot* parent, ctlPoint pos, unsigned length,  
			ctlScrollDirection dir = ctlScrollDirection::vertical, 
			const ctlStyleBase& style = ctlStyleGradient(
			ctlStyleGradient::common).changeToScroll(), 
			const ctlStyleBase& buttonStyle = ctlStyleGradient(
			ctlStyleGradient::common));
	public:
		//设置逻辑上可以滚动的最大距离（不是滚动条的实际长度）
		//如果 keepPos 为 true，则逻辑距离不变
		//否则已滚动的百分比不变
		bool setMaxLogicLength(int length, bool keepPos = true);
		int getMaxLogicLength();
		//设置或获取已经滚动的百分比
		bool setScrolledPercent(float percent);
		float getScrolledPercent();
		//设置或获取已经滚动的逻辑距离
		int getScrolledLogicLength();
		bool setScrolledLogicLength(int logicLength);
		bool addScrolledLogicLength(int logicLength);
	public:
		//获取滚动条的方向
		ctlScrollDirection getScrollDirection();
		//如果滚动条是垂直的，操作的属性高度，否则是宽度
		int getRealLength();
		bool setRealLength(int length);
		//如果滚动条是垂直的，操作的属性宽度，否则是高度
		int getRealScrollSize();
		bool setRealScrollSize(int size);
		//获取扣除按钮后的长度
		int getRealLengthWithoutButton();
		//获得可以滚动的真实长度
		int getRealScrollableLength();
		//设置或获取每滚动一次（通过按钮或鼠标滚轮）的长度
		void setLogicStep(int step);
		int getLogicStep();
		//处理 wheel 事件通告
		void dealMouseWheelEvent(ctlMouseEvent*);
	public:
		//设置按钮样式
		void setButtonStyle(const ctlStyleBase& style);
		//获取按钮
		ctlButton* getTopButton();
		ctlButton* getBottomButton();
		ctlButton* getBarButton();
	protected:
		virtual void _redraw_(_ctlInterior::drawInfo *);
		virtual void _position_event_(ctlPositionEvent*);
		virtual void _mouse_event_(ctlMouseEvent*);
		virtual void _key_event_(ctlKeyEvent*);
	private:
		void _flush_scroll_bar_length();
		ctlButton _scroll_top, _scroll_bottom, _scroll_bar;
		ctlScrollDirection _scroll_direction;
		std::atomic_int _scroll_scrolled_logic_length;
		int _scroll_logic_length;
		int _scroll_logic_step;
	};
#pragma warning(pop)

	inline void ctlScroll::dealMouseWheelEvent(ctlMouseEvent* me)
	{
		setScrolledLogicLength(getScrolledLogicLength() - 
				me->wheelDelta * getLogicStep());
	}
	inline bool ctlScroll::addScrolledLogicLength(int delta) {
		return setScrolledLogicLength(getScrolledLogicLength() + delta);
	}
	inline void ctlScroll::setButtonStyle(const ctlStyleBase& style) {
		lockDrawing();
		getTopButton()->setStyle(style);
		getBottomButton()->setStyle(style);
		getBarButton()->setStyle(style);
		unlockDrawing();
		redraw();
	}
	inline void ctlScroll::setLogicStep(int step) {
		_scroll_logic_step = step;
	}
	inline int ctlScroll::getLogicStep() {
		return _scroll_logic_step;
	}
	inline int ctlScroll::getRealScrollableLength() {
		if(getScrollDirection() == ctlScrollDirection::vertical)
			return getRealLengthWithoutButton() - getBarButton()->getHeight();
		return getRealLengthWithoutButton() - getBarButton()->getWidth();
	}
	inline int ctlScroll::getMaxLogicLength() {
		return _scroll_logic_length;
	}
	inline bool ctlScroll::setScrolledPercent(float percent) {
		return setScrolledLogicLength(unsigned(percent * getMaxLogicLength()));
	}
	inline float ctlScroll::getScrolledPercent() {
		return float(getScrolledLogicLength()) / float(getMaxLogicLength());
	}
	inline int ctlScroll::getScrolledLogicLength() {
		return _scroll_scrolled_logic_length;
	}
	inline ctlScrollDirection ctlScroll::getScrollDirection() {
		return _scroll_direction;
	}
	inline int ctlScroll::getRealLength() {
		if(getScrollDirection() == ctlScrollDirection::vertical)
			return getHeight();
		return getWidth();
	}
	inline bool ctlScroll::setRealLength(int length) 
	{
		if(getScrollDirection() == ctlScrollDirection::vertical)
			return size(getWidth(), length);
		return size(length, getHeight());
	}
	inline int ctlScroll::getRealScrollSize() {
		if(getScrollDirection() == ctlScrollDirection::horizontal)
			return getHeight();
		return getWidth();
	}
	inline bool ctlScroll::setRealScrollSize(int siz) {
		if(getScrollDirection() == ctlScrollDirection::horizontal)
			return size(getWidth(), siz);
		return size(siz, getHeight());
	}
	inline int ctlScroll::getRealLengthWithoutButton() {
		return getRealLength() - 2 * getRealScrollSize() + 2;
	}
	inline ctlButton* ctlScroll::getTopButton() {
		return &_scroll_top;
	}
	inline ctlButton* ctlScroll::getBottomButton() {
		return &_scroll_bottom;
	}
	inline ctlButton* ctlScroll::getBarButton() {
		return &_scroll_bar;
	}
}

#endif